package com.example.grainmall.fileutils.utils;

import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.*;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件处理工具类
 */
public class FileUtils {

    /**
     * 文件压缩——————————————————————————————————————————————————————————————————————————————————————————————————————————
     */

    /**
     * （压缩文件：一般压缩比）
     * 将目录压缩为 .zip 文件。
     *
     * @param sourceDirectoryPath 需压缩的目录的路径
     * @param zipFilePath         目标 .zip 文件路径
     * @throws IOException 如果处理过程中出现错误
     */
    public static void compressDirectoryToZipFile(String sourceDirectoryPath, String zipFilePath) throws IOException {
        Path sourceDir = Paths.get(sourceDirectoryPath);
        try (ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
            Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    outputStream.putNextEntry(new ZipEntry(sourceDir.relativize(file).toString()));
                    Files.copy(file, outputStream);
                    outputStream.closeEntry();
                    return FileVisitResult.CONTINUE;
                }
            });
        }
    }


    /**
     * 将目录压缩为 .zip 文件。对compressDirectoryToZipFile的拆分
     *
     * @param sourceDirectoryPath 需压缩的目录路径
     * @param zipFilePath 目标 .zip 文件路径
     * @throws IOException 如果处理过程中出现错误
     */
    public static void compressDirectoryToZipFile2(String sourceDirectoryPath, String zipFilePath) throws IOException {
        Path sourceDir = Paths.get(sourceDirectoryPath);
        try (ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
            Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//                  提取到 addToZipEntry 方法以提高代码可读性
                    addToZipEntry(outputStream, file, sourceDir.relativize(file).toString());
                    return FileVisitResult.CONTINUE;
                }
            });
        }
    }

    /**
     * 将文件添加到 zip 条目。
     *
     * @param outputStream 文件需添加到的 ZipOutputStream
     * @param file 需添加的文件路径
     * @param zipEntryName .zip 条目名
     * @throws IOException 如果处理过程中出现错误
     */
    private static void addToZipEntry(ZipOutputStream outputStream, Path file, String zipEntryName) throws IOException {
        outputStream.putNextEntry(new ZipEntry(zipEntryName));
        Files.copy(file, outputStream);
        outputStream.closeEntry();
    }




    /**
     * 文件上传下载（本地）———————————————————————————————————————————————————————————————————————————————————————————————————————
     */


    private static final String UPLOAD_FOLDER = "C:/uploads/";

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        byte[] bytes = file.getBytes();
        Path path = Paths.get(UPLOAD_FOLDER + file.getOriginalFilename());
        Files.write(path, bytes);

        return "Upload completed";
    }


    @GetMapping("/download")
    public ResponseEntity<Resource> downloadFile(@RequestParam("fileName") String fileName) throws IOException {
        Path filePath = Paths.get(UPLOAD_FOLDER).toAbsolutePath().resolve(fileName);
        Resource resource = new UrlResource(filePath.toUri());

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }


    /**
     * 文件上传下载（远程）———————————————————————————————————————————————————————————————————————————————————————————————————————
     */

    /**
     * RestTemplate 方式
     */
    @PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
        String serverUrl = "<SERVER_URL>";  // 远程服务器的URL

        MultipartBodyBuilder builder = new MultipartBodyBuilder();
        builder.part("file", file.getResource(), MediaType.MULTIPART_FORM_DATA)
                .filename(file.getOriginalFilename());

        MultiValueMap<String, HttpEntity<?>> multipartBody = builder.build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String, HttpEntity<?>>> requestEntity = new HttpEntity<>(multipartBody, headers);

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(serverUrl, HttpMethod.POST, requestEntity, String.class);

        return "Uploaded: " + response.getBody();
    }

    /**
     * WebClient 方式
     */

    @PostMapping("/upload")
    public Mono<String> upload(@RequestPart("file") FilePart filePart) {
        String serverUrl = "<SERVER_URL>";  // 远程服务器的URL

        // 创建WebClient
        WebClient webClient = WebClient.create(serverUrl);

        // 创建MultiValueMap用于设置multipart文件
        MultiValueMap<String, Object> data = new LinkedMultiValueMap<>();
        data.add("file", filePart);

        return webClient.post()
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(data))
                .retrieve()
                .bodyToMono(String.class);
    }

    @GetMapping("/download")
    public Mono<InputStreamResource> download() {
        String serverUrl = "<SERVER_URL>";  // 远程服务器的URL

        // 创建WebClient
        WebClient webClient = WebClient.create(serverUrl);

        return webClient.get()
                .retrieve()
                .bodyToMono(InputStreamResource.class);
    }



    /**
     * PDF生成———————————————————————————————————————————————————————————————————————————————————————————————————————————
     */


    /**
     * 电子印章生成———————————————————————————————————————————————————————————————————————————————————————————————————————
     */


    /**
     * Excel生成，或处理———————————————————————————————————————————————————————————————————————————————————————————————————————
     */



}
